﻿using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Transactions;
using Newtonsoft.Json;
using T.ServiceComponent.Database.Service;
using T.FAS.Runtime.DataModel.Dao;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.ServiceComponent.Error;
using T.FAS.Runtime.Base.Entity;
//using T.FAS.Authority.MetaData.Dev.Plugin;
//using T.FAS.Authority.MetaData.Entity;

namespace T.FAS.Runtime.DataModel.Dao
{
    public class StateMachineMetadataLogic
    {
        #region Fields & Properties
        public const string MetaDataID = DataModelConst.StateMachineMetaType;
        public const string MetaDataName = "状态机";

        private readonly StateMachineMetadataELBDao _stateMachineDao = new StateMachineMetadataELBDao(); 
        private readonly StateMachineStateELBDao _stateMachineStateELBDao = new StateMachineStateELBDao();
        private readonly StateMachineEventELBDao _stateMachineEventELBDao = new StateMachineEventELBDao();
        private readonly StateMachineTransitionELBDao _stateMachineTransitionELBDao = new StateMachineTransitionELBDao();
        private readonly StateMachineActionELBDao _stateMachineActionELBDao = new StateMachineActionELBDao();
        private readonly StateMachineRuleELBDao _stateMachineRuleELBDao = new StateMachineRuleELBDao();
        private readonly StateMachineRuleFieldELBDao _stateMachineRuleFieldELBDao = new StateMachineRuleFieldELBDao();
        private readonly StateMachineRuleContentELBDao _stateMachineRuleContentELBDao = new StateMachineRuleContentELBDao();
        private readonly StaticDataObjectLogic _staticDataObjectLogic = new StaticDataObjectLogic();
        //private readonly BizPermissionObjectManager _bizPermissionObjectManager = new BizPermissionObjectManager();
        #endregion

        #region 获取元数据信息
        /// <summary>
        /// 根据主键id获取状态机
        /// </summary>
        /// <param name="stateMachineID"></param>
        /// <returns></returns>
        public StateMachineMetadata GetStateMachineMetadataByID(string stateMachineID)
        {
            var sm = _stateMachineDao.GetStateMachineMetadataByID(stateMachineID);
            InitializeMetadata(sm);
            BuildMetaDataRef(sm);
            //PackagingDependencyMetaData(sm);
            return sm;
        }

        /// <summary>
        /// 获取状态机列表
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public List<StateMachineMetadata> GetStateMachineMetadatas(Dictionary<string, string> filter)
        {
            var list = _stateMachineDao.GetStateMachineMetadatas(filter);
            list.ForEach(sm =>
            {
                InitializeMetadata(sm);
                PackagingDependencyMetaData(sm);
            });
            return list;
        }

        /// <summary>
        /// 根据CDOid获取状态机列表集合，未做初始化处理，只包含状态机基本信息
        /// </summary>
        /// <param name="cdoId"></param>
        /// <param name="ColumnName"></param>
        /// <returns></returns>
        public List<StateMachineMetadata> GetStateMachineMetadatas(string cdoId)
        {
            return _stateMachineDao.GetStateMachineByCDO(cdoId);
        }

        private Dictionary<int, string> GetStates(StateMachineMetadata stateMachine)
        {
            Dictionary<int, string> States = new Dictionary<int, string>();
            foreach (var state in stateMachine.States)
            {
                States.Add(state.Key, state.Name);
            }
            return States;
        }

        /// <summary>
        /// 根据主键id获取状态机
        /// </summary>
        /// <param name="StateMachineMetadataID"></param>
        /// <returns></returns>
        public List<StateMachineMetadata> GetStateMachineByCDOColumn(string cdoId, string stateColKey)
        {
            if (string.IsNullOrEmpty(cdoId) || string.IsNullOrEmpty(stateColKey))
                return null;
            var StateMachineMetadata = _stateMachineDao.GetStateMachineByCDOColumn(cdoId, stateColKey);
            if (StateMachineMetadata != null && StateMachineMetadata.Count > 0)
            {
                foreach (var machine in StateMachineMetadata)
                {
                    PackagingDependencyMetaData(machine);
                }
            }
            return StateMachineMetadata;
        }

        /// <summary>
        /// 初始化填充状态机实例的属性关系引用，区别于Dao层的Initialize方法（从数据库中拉取状态机数据，而不是建立引用关系）
        /// 用途：设计时填充元数据，运行时反序列化后填充元数据
        /// </summary>
        /// <returns></returns>
        public StateMachineMetadata PackagingDependencyMetaData(StateMachineMetadata stateMachine)
        {
            if (stateMachine == null)
                return null;
            //运行时用不到SM关联的CDO与SDO，为了优化设计时SM打开速度，这里不再直接查出CDO SDO数据，由前端自行调用GetMetaData统一查询

            //初始化状态机权限BPO对象以及OP
            if (!string.IsNullOrEmpty(stateMachine.BPOID))
            {
                /* Todo
                stateMachine.BPO = _bizPermissionObjectManager.GetMetaDataContent(stateMachine.BPOID) as BizPermissionObject;
                if (stateMachine.BPO != null && stateMachine.Events != null)
                {
                    foreach (var tEvent in stateMachine.Events)
                    {
                        tEvent.OP = stateMachine.BPO.BizOperations.FirstOrDefault(op => op.Id == tEvent.OPID);
                    }
                }
                */
            }
            return stateMachine;
        }

        /// <summary>
        /// 构造SM实体引用
        /// </summary>
        /// <param name="stateMachine"></param>
        public void BuildMetaDataRef(StateMachineMetadata stateMachine)
        {
            if (stateMachine == null)
                return;
            if (stateMachine.Transitions != null && stateMachine.Transitions.Count > 0)
            {
                foreach (var tran in stateMachine.Transitions)
                {
                    tran.From = stateMachine.States?.FirstOrDefault(s => s.ID == tran.FromStateID);
                    tran.To = stateMachine.States?.FirstOrDefault(s => s.ID == tran.ToStateID);
                    tran.Event = stateMachine.Events?.FirstOrDefault(e => e.ID == tran.EventID);
                }
            }
        }

        /// <summary>
        /// 从DB中拉取完整元数据信息，注意不要传null到前端，返回空数组
        /// </summary>
        /// <param name="stateMachine"></param>
        /// <returns></returns>
        public StateMachineMetadata InitializeMetadata(StateMachineMetadata stateMachine)
        {
            if (stateMachine == null) return null;
            var smid = stateMachine.ID;
            var allEvents = _stateMachineEventELBDao.GetTEventsByForeignKey(smid);
            var allTrans = _stateMachineTransitionELBDao.GetTTransitionsByForeignKey(smid);
            var allActions = _stateMachineActionELBDao.GetByMetaDataForeignKey(smid).GroupBy(a => a.TransitionID);
            var allStates = _stateMachineStateELBDao.GetTStatesByForeignKey(smid);
            var allRules = _stateMachineRuleELBDao.GetByMetaDataForeignKey(smid).GroupBy(r => r.StateID);
            var allRuleContent = _stateMachineRuleContentELBDao.GetByMetaDataForeignKey(smid).GroupBy(c => c.RuleID);
            var allRuleFields = _stateMachineRuleFieldELBDao.GetByMetaDataForeignKey(smid).GroupBy(r => r.RuleID);

            stateMachine.States = allStates ?? new List<TState>();
            stateMachine.Transitions = allTrans ?? new List<TTransition>();
            stateMachine.Events = allEvents ?? new List<TEvent>();
            foreach (var state in stateMachine.States)
            {
                state.Rules = allRules.FirstOrDefault(r => r.Key == state.ID)?.ToList() ?? new List<TRule>();
                if (state.Rules != null && state.Rules.Count > 0)
                {
                    foreach (var rule in state.Rules)
                    {
                        rule.RuleFields = allRuleFields.FirstOrDefault(r => r.Key == rule.ID)?.ToList() ?? new List<TRuleField>();
                        rule.RuleContents = allRuleContent.FirstOrDefault(r => r.Key == rule.ID)?.ToList() ?? new List<TRuleContent>();
                    }
                }
            }
            foreach (var tran in stateMachine.Transitions)
            {
                tran.Actions = allActions.FirstOrDefault(r => r.Key == tran.ID)?.ToList() ?? new List<TAction>();
            }
            return stateMachine;
        }
        #endregion

        #region 新增
        /// <summary>
        /// 保存状态机
        /// </summary>
        /// <param name="stateMachine"></param>
        public void SaveStateMachineMetadata(StateMachineMetadata stateMachine)
        { 
            if (string.IsNullOrEmpty(stateMachine.SDOID))
            {
                throw new FasException(DataModelErrorCode.SM.CreateError, $"{MetaDataName}保存失败，SDOID字段不能为空");
            }
            //处理States，给系统默认字段赋值
            if (stateMachine.States != null && stateMachine.States.Count > 0)
            {
                int sort = 0;
                foreach (var state in stateMachine.States)
                {
                    state.Sort = sort++;
                    EntityTools.FillSystemFiledForAdd(state, stateMachine);
                    if (string.IsNullOrEmpty(state.ID))
                        state.ID = Guid.NewGuid().ToString();
                    state.StateMachineID = stateMachine.ID;
                    if (state.Rules != null && state.Rules.Count > 0)
                    {
                        foreach (var rule in state.Rules)
                        {
                            //处理规则内容
                            int contentSort = 0;
                            if (string.IsNullOrEmpty(rule.ID))
                                rule.ID = Guid.NewGuid().ToString();
                            rule.StateID = state.ID;
                            rule.StateMachineID = stateMachine.ID;

                            //处理规则内容
                            if (rule.RuleContents != null && rule.RuleContents.Count > 0)
                            {
                                foreach (var cont in rule.RuleContents)
                                {
                                    cont.Sort = contentSort++;
                                    EntityTools.FillSystemFiledForAdd(cont, stateMachine);
                                    if (string.IsNullOrEmpty(cont.ID))
                                        cont.ID = Guid.NewGuid().ToString();
                                    cont.RuleID = rule.ID;
                                    cont.StateID = state.ID;
                                    cont.StateMachineID = stateMachine.ID;
                                }
                            }
                            //处理规则作用列
                            int ruleSort = 0;
                            if (rule.RuleFields != null && rule.RuleFields.Count > 0)
                            {
                                foreach (var field in rule.RuleFields)
                                {
                                    field.Sort = ruleSort++;
                                    EntityTools.FillSystemFiledForAdd(field, stateMachine);
                                    if (string.IsNullOrEmpty(field.ID))
                                        field.ID = Guid.NewGuid().ToString();
                                    field.RuleID = rule.ID;
                                    field.StateID = state.ID;
                                    field.StateMachineID = stateMachine.ID;
                                }
                            }
                            EntityTools.FillSystemFiledForAdd(rule, stateMachine);
                        }
                    }
                }
            }
            //处理Events，给系统默认字段赋值
            if (stateMachine.Events != null && stateMachine.Events.Count > 0)
            {
                foreach (var @event in stateMachine.Events)
                {
                    if (string.IsNullOrEmpty(@event.ID))
                        @event.ID = Guid.NewGuid().ToString();
                    @event.StateMachineID = stateMachine.ID;
                    EntityTools.FillSystemFiledForAdd(@event, stateMachine);
                }
            }
            //处理Source，给系统默认字段赋值
            if (stateMachine.Transitions != null && stateMachine.Transitions.Count > 0)
            {
                foreach (var tran in stateMachine.Transitions)
                {
                    if (string.IsNullOrEmpty(tran.ID))
                        tran.ID = Guid.NewGuid().ToString();
                    tran.StateMachineID = stateMachine.ID;
                    EntityTools.FillSystemFiledForAdd(tran, stateMachine);
                    if (tran.Actions != null && tran.Actions.Count > 0)
                    {
                        foreach (var action in tran.Actions)
                        {
                            if (string.IsNullOrEmpty(action.ID))
                                action.ID = Guid.NewGuid().ToString();
                            action.TransitionID = tran.ID;
                            action.StateMachineID = stateMachine.ID;
                            EntityTools.FillSystemFiledForAdd(action, stateMachine);
                        }
                    }
                }
            }

            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions(){IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted}))
                {
                    _stateMachineDao.SaveStateMachineMetadata(stateMachine);
                    var allStates = stateMachine.States;
                    var allEvents = stateMachine.Events;
                    var allTrans = stateMachine.Transitions;
                    var allActions = allTrans?.Where(t => t.Actions != null)?.SelectMany(t => t.Actions)?.ToList();
                    var allRules = allStates?.Where(t => t.Rules != null)?.SelectMany(t => t.Rules)?.ToList();
                    var allRuleContent = allRules?.Where(t => t.RuleContents != null)?.SelectMany(r => r.RuleContents)?.ToList();
                    var allRuleFields = allRules?.Where(t => t.RuleFields != null)?.SelectMany(r => r.RuleFields)?.ToList();

                    _stateMachineEventELBDao.CreateTEvent(allEvents);
                    _stateMachineTransitionELBDao.CreateTTransition(allTrans);
                    _stateMachineActionELBDao.CreateTAction(allActions);
                    _stateMachineStateELBDao.CreateTState(allStates);
                    _stateMachineRuleELBDao.CreateTRule(allRules);
                    _stateMachineRuleContentELBDao.CreateTRuleContent(allRuleContent);
                    _stateMachineRuleFieldELBDao.CreateTRuleField(allRuleFields);
                    //同步更新SDO预置数据
                    _staticDataObjectLogic.SyncPresetData(stateMachine.SDOID, GetStates(stateMachine));
                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.SM.CreateError, $"{MetaDataName}元数据保存失败", e);
            }
        }

        #endregion

        #region 删除
        /// <summary>
        /// 删除StateMachine
        /// </summary>
        /// <param name="stateMachineID"></param>
        public void DeleteStateMachineMetadata(string stateMachineID)
        {
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions(){IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted}))
                {
                    _stateMachineDao.DeleteStateMachineMetadata(stateMachineID);
                    _stateMachineEventELBDao.DeleteTEventByForeignKey(stateMachineID);
                    _stateMachineTransitionELBDao.DeleteTTransitionByForeignKey(stateMachineID);
                    _stateMachineActionELBDao.DeleteByMetaDataForeignKey(stateMachineID);
                    _stateMachineStateELBDao.DeleteTStateByForeignKey(stateMachineID);
                    _stateMachineRuleELBDao.DeleteByMetaDataForeignKey(stateMachineID);
                    _stateMachineRuleContentELBDao.DeleteByMetaDataForeignKey(stateMachineID);
                    _stateMachineRuleFieldELBDao.DeleteByMetaDataForeignKey(stateMachineID);
                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.SM.DeleteError, $"{MetaDataName}元数据删除失败", e);
            }
        }

        #endregion

        #region 其它
        /// <summary>
        /// 一个CDO的状态字段只能绑定一个状态机
        /// </summary>
        /// <param name="sm"></param>
        /// <returns>true:通过校验，false:不满足唯一性校验</returns>
        public bool UniqueCheck(StateMachineMetadata stateMachine)
        {
            return _stateMachineDao.UniqueCheck(stateMachine);
        }

        #endregion
    }
}
